package com.koc.robot;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES11;
import android.util.Log;

import com.koc.robot.common.Vector;
import com.koc.robot.common.Vector3;

public class Map {

	private Scene mScene;
	
	private Block mBlocks[][][];
	
	private int mMapWidth;
	private int mMapHeight;
	private int mMapDepth;
	private String mName;
	private String mText;
	private float mGoalTime;
	private int mGoalSteps;
	private int mGoalWraps;
	private int mCoinNum;
	
	private BlockPoint mMapStartPoint = new BlockPoint();	//indicate start position
	private BlockPoint mMapCoins[];
	private Coin mCoins[];
	
	//for render. 0 is faces, 1 is grids
	private int mVertexBufferID[] = new int[2];
	
	private int mVertexArrays1[] = null;
	private int mVertexArrays2[] = null;
	
	private int mIndexBufferID[] = new int[2];
	private FloatBuffer mVertexBuffer[] = new FloatBuffer[2];
	private ShortBuffer mIndexBuffer[] = new ShortBuffer[2]; 
	private int mVertBufferOffset[] = new int[2];
	
	static final int PER_VERTEX_POINT_WORD_NUM = 3 + 1; //2 words for vertex, 1 word for color
    static final int PER_VERTEX_POINT_BUFFER_SIZE = PER_VERTEX_POINT_WORD_NUM * 4;
    static final int COLOR_BUFFER_OFFSET = 3 * 4;
    static final int PRE_FACE_VERTEX_BUFFER_SIZE = 4 * PER_VERTEX_POINT_BUFFER_SIZE;
 //   static final int GRID_VERTEX_BUFFER_SIZE = 4 * PER_VERTEX_POINT_BUFFER_SIZE;
	private static final int MAX_FACES_NUM = 200;
	private static final int MAX_VERTEX_BUFFER_SIZE = MAX_FACES_NUM * PRE_FACE_VERTEX_BUFFER_SIZE;
	private static final int MAX_FACE_INDEX_BUFFER_SIZE = MAX_FACES_NUM * 6 * 2;
	private static final int MAX_GRID_INDEX_BUFFER_SIZE = MAX_FACES_NUM * 8 * 2;
	
	private static final String MAPFOLDER = "maps/";
	private static final String MAPTEXTFILEEXT = ".txt";
	private static final String MAPIMAGEFILEEXT = ".png";
	
	static final float DEPTH_INTERVAL = 0.001f;
	
	public Map(Scene scene)
	{
		mMapWidth = 0;
		mMapHeight = 0;
		mMapDepth = 0;
		mScene = scene;
		
		intBufferes();
		for(int i = 0; i < 2; ++i)
		{
			mVertBufferOffset[i] = 0;
		}
	}
	
	private void intBufferes()
	{
	    ByteBuffer vfb0 = ByteBuffer.allocateDirect(MAX_VERTEX_BUFFER_SIZE); 
	    vfb0.order(ByteOrder.nativeOrder());
	    mVertexBuffer[0] = vfb0.asFloatBuffer();	    	
	    ByteBuffer idxb0 = ByteBuffer.allocateDirect(MAX_FACE_INDEX_BUFFER_SIZE);
	    idxb0.order(ByteOrder.nativeOrder());
	    mIndexBuffer[0] = idxb0.asShortBuffer();
	    for(int i = 0; i < MAX_FACES_NUM; ++i)
	    {
	    	mIndexBuffer[0].put((short)(i * 4 + 0));
	    	mIndexBuffer[0].put((short)(i * 4 + 1));
	    	mIndexBuffer[0].put((short)(i * 4 + 2));
	    	mIndexBuffer[0].put((short)(i * 4 + 0));
	    	mIndexBuffer[0].put((short)(i * 4 + 2));
	    	mIndexBuffer[0].put((short)(i * 4 + 3));
	    }
	    mIndexBuffer[0].position(0);
	    
	    ByteBuffer vfb1 = ByteBuffer.allocateDirect(MAX_VERTEX_BUFFER_SIZE); 
	    vfb1.order(ByteOrder.nativeOrder());
	    mVertexBuffer[1] = vfb1.asFloatBuffer();	    	
	    ByteBuffer idxb1 = ByteBuffer.allocateDirect(MAX_GRID_INDEX_BUFFER_SIZE);
	    idxb1.order(ByteOrder.nativeOrder());
	    mIndexBuffer[1] = idxb1.asShortBuffer();
	    for(int i = 0; i < MAX_FACES_NUM; ++i)
	    {
	    	mIndexBuffer[1].put((short)(i * 4 + 0));
	    	mIndexBuffer[1].put((short)(i * 4 + 1));
	    	mIndexBuffer[1].put((short)(i * 4 + 1));
	    	mIndexBuffer[1].put((short)(i * 4 + 2));
	    	mIndexBuffer[1].put((short)(i * 4 + 2));
	    	mIndexBuffer[1].put((short)(i * 4 + 3));
	    	mIndexBuffer[1].put((short)(i * 4 + 3));
	    	mIndexBuffer[1].put((short)(i * 4 + 0));
	    }
	    mIndexBuffer[1].position(0);
		
		int vboIDs[] = new int[4];
		GLES11.glGenBuffers(4, vboIDs, 0);
		mVertexBufferID[0] = vboIDs[0];
		mVertexBufferID[1] = vboIDs[1];
		mIndexBufferID[0] = vboIDs[2];
		mIndexBufferID[1] = vboIDs[3];
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[0]);
		GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, mVertexBuffer[0].capacity() * 4,
				mVertexBuffer[0], GLES11.GL_DYNAMIC_DRAW);
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID[0]);
		GLES11.glBufferData(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer[0].capacity() * 2, 
				mIndexBuffer[0], GLES11.GL_STATIC_DRAW);
		
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[1]);
		GLES11.glBufferData(GLES11.GL_ARRAY_BUFFER, mVertexBuffer[1].capacity() * 4,
				mVertexBuffer[1], GLES11.GL_DYNAMIC_DRAW);
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID[1]);
		GLES11.glBufferData(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer[1].capacity() * 2, 
				mIndexBuffer[1], GLES11.GL_STATIC_DRAW);
		
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, 0);
		
		mVertexArrays1 = new int[mVertexBuffer[0].capacity()];
		mVertexArrays2 = new int[mVertexBuffer[1].capacity()];
	}
	
	public int getMapWidth()
	{
		return mMapWidth;
	}
	
	public int getMapHeight()
	{
		return mMapHeight;
	}
	
	public int getMapDepth()
	{
		return mMapDepth;
	}
 	
	public Block getBlock(int x, int y, int z)
	{
		return mBlocks[x][y][z];
	}
	
	public Block getBlock(BlockPoint p)
	{
		return mBlocks[p.x][p.y][p.z];
	}
	
	public boolean isValidBlock(int x, int y, int z)
	{
		return mBlocks[x][y][z].mTileNum != Block.INVALID_TILENUM;
	}
	
	public boolean isValidBlock(BlockPoint p)
	{
		return mBlocks[p.x][p.y][p.z].mTileNum != Block.INVALID_TILENUM;
	}
	
	public boolean load(String mapName)
	{
 		String mapTextFile = MAPFOLDER + mapName + MAPTEXTFILEEXT;
		boolean bSuccessed = loadMapTextFile(mapTextFile);
		if(bSuccessed != true)
			return false;
				
		
		Bitmap imageData = null;
		try
		{
			String mapImageFile = MAPFOLDER + mapName + MAPIMAGEFILEEXT;
	        InputStream is = Global.context.getAssets().open(mapImageFile);
	        if(is != null)
	        	imageData = BitmapFactory.decodeStream(is);		
		}
		catch(Exception e)
		{
			
		}
		
		if(imageData == null)
			return false;
		
		mMapWidth = imageData.getWidth();
		mMapDepth = imageData.getHeight()/ mMapHeight;
		
		mBlocks = new Block[mMapWidth][mMapHeight][mMapDepth];
		mMapCoins = new BlockPoint[mCoinNum];
		mCoins = new Coin[mCoinNum];
		
		for(int y = 0; y < mMapHeight; ++y)
			for(int z = 0 ; z < mMapDepth; ++z)
				for(int x = 0; x < mMapWidth; ++x)
				{
					int pixelColor = imageData.getPixel(x, y * mMapDepth + z);
					int a = (pixelColor >> 24) & 0xFF;
					int r = (pixelColor >> 16) & 0xFF;
					int g = (pixelColor >> 8) & 0xFF ;
					int b = pixelColor & 0xFF;
					
					mBlocks[x][mMapHeight - y - 1][mMapDepth - z - 1] = new Block(this);
					
					for(int i = 0; i < BlockCommon.TILES_COLORS.length; ++i)
					{
						if(BlockCommon.TILES_COLORS[i] == Util.toColor(r, g, b))
						{
							mBlocks[x][mMapHeight - y - 1][mMapDepth - z - 1].mTileNum = i;
							mBlocks[x][mMapHeight - y - 1][mMapDepth - z - 1].mFaceColor = BlockCommon.BLOCK_COLORS[i];
							mBlocks[x][mMapHeight - y - 1][mMapDepth - z - 1].mGridColor = BlockCommon.GRID_COLORS[i];
							break;
						}
					}
					
					int coinIdx = 0;
					for(int i = 0; i < BlockCommon.SPECIAL_COLORS.length; ++i)
					{
						if(BlockCommon.SPECIAL_COLORS[i] == Util.toColor(r, g, b))
						{
							mBlocks[x][mMapHeight - y - 1][mMapDepth - z - 1].mTileNum = Block.INVALID_TILENUM;
							
							if(i == 0)
							{
								mMapStartPoint.x = x;
								mMapStartPoint.y = (mMapHeight - y - 1) - 1;
								mMapStartPoint.z = mMapDepth - z - 1;
								
								mScene.getPlayer().initPosition(mMapStartPoint);
							}
							else // i == 1
							{
								boolean good = true;
								//TODO: check whether coin had be collected
								if(coinIdx < mCoinNum)
								{
									mMapCoins[coinIdx] = new BlockPoint();
									mMapCoins[coinIdx].x = x;
									mMapCoins[coinIdx].y = (mMapHeight - y - 1) - 1;
									mMapCoins[coinIdx].z = mMapDepth - z - 1;
									
									mCoins[coinIdx] = new Coin(mScene);
								//	mCoins[coinIdx].init();
									mCoins[coinIdx].initPosition(mMapCoins[coinIdx]);
									
									coinIdx++;
								}
							}
						}
					}					
				}
		
		updateBlockVisible();
		return true;
	}
	
	private boolean loadMapTextFile(String fileName)
	{
		InputStream in = null;
		try
		{
			in = Global.context.getAssets().open(fileName);
		}
		catch(Exception e)
		{			
		}
		
		if(in == null)
			return false;
		
		try
		{
			InputStreamReader inR = new InputStreamReader(in); 
			BufferedReader buf = new BufferedReader (  inR  ) ; 
			String line; 
			try
			{
				while((line = buf.readLine()) != null)   
				{  
					String params[] = line.split("=");
					if(params[0].equals("height"))
						mMapHeight = Integer.parseInt(params[1]);
					else if(params[0].equals("name"))
						mName = params[1];
					else if(params[0].equals("text"))
						mText = params[1];
					else if(params[0].equals("time"))
						mGoalTime = Float.parseFloat(params[1]);
					else if(params[0].equals("steps"))
						mGoalSteps = Integer.parseInt(params[1]);
					else if(params[0].equals("wraps"))
						mGoalWraps = Integer.parseInt(params[1]);
					else if(params[0].equals("coins"))
						mCoinNum = Integer.parseInt(params[1]);
				}  
			}
			catch(Exception e)
			{				
			}
		}  
		finally
		{  
			try
			{
				in.close (  ) ; 
			}
			catch(Exception e)
			{				
			}
		}
		
		return true;
	}
	
	void updateBlockVisible()
	{
		for(int x = 0; x < mMapWidth; ++x)
			for(int y = 0; y < mMapHeight; ++y)
				for(int z = 0; z < mMapDepth; ++z)
				{
					Block b = mBlocks[x][y][z];
					
					//side1
					if(z == mMapDepth - 1)
						b.mFaceVisiable[0] = true;
					else if(mBlocks[x][y][z + 1].mTileNum != Block.INVALID_TILENUM)
						b.mFaceVisiable[0] = false;
					else
						b.mFaceVisiable[0] = true;
					
					//side2
					if(x == mMapWidth - 1)
						b.mFaceVisiable[1] = true;
					else if(mBlocks[x + 1][y][z].mTileNum != Block.INVALID_TILENUM)
						b.mFaceVisiable[1] = false;
					else
						b.mFaceVisiable[1] = true;

					//side3
					if(z == 0)
						b.mFaceVisiable[2] = true;
					else if(mBlocks[x][y][z - 1].mTileNum != Block.INVALID_TILENUM)
						b.mFaceVisiable[2] = false;
					else
						b.mFaceVisiable[2] = true;
					
					//side4
					if(x == 0)
						b.mFaceVisiable[3] = true;
					else if(mBlocks[x - 1][y][z].mTileNum != Block.INVALID_TILENUM)
						b.mFaceVisiable[3] = false;
					else
						b.mFaceVisiable[3] = true;
					
					//top
					if(y == mMapHeight - 1)
						b.mFaceVisiable[4] = true;
					else if(mBlocks[x][y + 1][z].mTileNum != Block.INVALID_TILENUM)
						b.mFaceVisiable[4] = false;
					else
						b.mFaceVisiable[4] = true;
				}
	}
	
	void render()
	{
		long time1 = System.currentTimeMillis();
		//first, clear index
		for(int i = 0; i < 2; ++i)
		{
			mVertBufferOffset[i] = 0;
		}
		
		float rotation = mScene.getRotation();
		if(rotation >= Common.PI_125 && rotation < Common.PI_175)
		{
			//draw order x, -z, y
			for(int x = 0; x < mMapWidth; ++x)
				for(int z = mMapDepth - 1; z >= 0; --z)
					for(int y = 0; y < mMapHeight; ++y)
					{
						Vector pos = mScene.convertGRDToSCR(x, y, z);
						float depth = 0 - x * DEPTH_INTERVAL * mMapDepth + z * DEPTH_INTERVAL;
						mBlocks[x][y][z].draw(new Vector3(pos.x, pos.y, depth), mScene);
						
						drawObjects(x, y, z, true, true, false, depth);
					}
		}
		else if(rotation >= Common.PI_175 || rotation < Common.PI_025)
		{
			//draw: Z, X, Y
			for(int z = 0 ; z < mMapDepth; ++z)
				for(int x = 0; x < mMapWidth; ++x)
					for(int y = 0; y < mMapHeight; ++y)
					{
						Vector pos = mScene.convertGRDToSCR(x, y, z);
						float depth = 0 - z * DEPTH_INTERVAL * mMapWidth - x * DEPTH_INTERVAL;
						if(mBlocks[x][y][z].mTileNum != Block.INVALID_TILENUM)
							mBlocks[x][y][z].draw(new Vector3(pos.x, pos.y, depth), mScene);
						
						drawObjects(x, y, z, true, true, true, depth);
					}
		}
		else if(rotation >= Common.PI_025 && rotation < Common.PI_075)
		{
			//draw order: -x, z, y
			for(int x = mMapWidth - 1; x >= 0; --x)
				for(int z = 0; z < mMapDepth; ++z)
					for(int y = 0; y < mMapHeight; ++y)
					{
						Vector pos = mScene.convertGRDToSCR(x, y, z);
						float depth = 0 + x * DEPTH_INTERVAL * mMapDepth - z * DEPTH_INTERVAL;
						mBlocks[x][y][z].draw(new Vector3(pos.x, pos.y, depth), mScene);
						
						drawObjects(x, y, z, false, true, true, depth);
					}
		}
		else // rotation >= Common.PI_075 && rotation < Common.PI_125
		{
			//draw order: -z, -x, y
			for(int z = mMapDepth - 1; z >= 0; --z)
				for(int x = mMapWidth - 1; x >= 0; --x)
					for(int y = 0; y < mMapHeight; ++y)
					{
						Vector pos = mScene.convertGRDToSCR(x, y, z);
						float depth = 0 + z * DEPTH_INTERVAL * mMapWidth + x * DEPTH_INTERVAL;
						mBlocks[x][y][z].draw(new Vector3(pos.x, pos.y, depth), mScene);
						
						drawObjects(x, y, z, false, true, false, depth);
					}
		}
		
		long time2 = System.currentTimeMillis();
		doDraw();
	
		long time3 = System.currentTimeMillis();
//		Log.d("render time", String.valueOf(time2 - time1) + "   " + String.valueOf(time3 - time2));
	}
	
	private void doDraw()
	{
		// first, fill the buffer
		IntBuffer buffer = IntBuffer.wrap(mVertexArrays1);
		buffer.position(0);
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[0]);
		GLES11.glBufferSubData(GLES11.GL_ARRAY_BUFFER, 0, mVertBufferOffset[0], buffer);
		
		buffer = IntBuffer.wrap(mVertexArrays2);
		buffer.position(0);
		
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[1]);
		GLES11.glBufferSubData(GLES11.GL_ARRAY_BUFFER, 0, mVertBufferOffset[0], buffer);
		
		GLES11.glDisable(GLES11.GL_TEXTURE_2D);
		GLES11.glEnableClientState(GLES11.GL_VERTEX_ARRAY);
		GLES11.glDisableClientState(GLES11.GL_TEXTURE_COORD_ARRAY);
		GLES11.glEnableClientState(GLES11.GL_COLOR_ARRAY);
		
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID[0]);
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[0]);
		GLES11.glVertexPointer(3, GLES11.GL_FLOAT, PER_VERTEX_POINT_BUFFER_SIZE, 0);
		GLES11.glColorPointer(4, GLES11.GL_UNSIGNED_BYTE, PER_VERTEX_POINT_BUFFER_SIZE, 
				COLOR_BUFFER_OFFSET);
		int drawVertNum = ((mVertBufferOffset[0] / PER_VERTEX_POINT_BUFFER_SIZE) / 4) * 6;
		GLES11.glDrawElements(GLES11.GL_TRIANGLES, drawVertNum, GLES11.GL_UNSIGNED_SHORT, 0);
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID[1]);
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[1]);
		GLES11.glVertexPointer(3, GLES11.GL_FLOAT, PER_VERTEX_POINT_BUFFER_SIZE, 0);
		GLES11.glColorPointer(4, GLES11.GL_UNSIGNED_BYTE, PER_VERTEX_POINT_BUFFER_SIZE, 
				COLOR_BUFFER_OFFSET);
		int drawgridVertNum = ((mVertBufferOffset[1] / PER_VERTEX_POINT_BUFFER_SIZE) / 4) * 8;
		GLES11.glDrawElements(GLES11.GL_LINES, drawgridVertNum, GLES11.GL_UNSIGNED_SHORT, 0);
		GLES11.glBindBuffer(GLES11.GL_ELEMENT_ARRAY_BUFFER, 0);
		GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, 0);	
		
		GLES11.glEnable(GLES11.GL_TEXTURE_2D);
		GLES11.glEnableClientState(GLES11.GL_VERTEX_ARRAY);
		GLES11.glEnableClientState(GLES11.GL_TEXTURE_COORD_ARRAY);
		GLES11.glDisableClientState(GLES11.GL_COLOR_ARRAY);
	}
	
	public void drawObjects(int x, int y, int z, boolean ceilX, boolean ceilY, boolean ceilZ, float depth)
	{
		//if has draw player, do not need flush map again
		boolean hasFlushedMap = drawPlayer(x, y, z, ceilX, ceilY, ceilZ, depth);
		
		for(int i = 0; i < mCoinNum; ++i)
		{
			if(mCoins[i] != null && !mCoins[i].hasCollected() && mCoins[i].isInBock(x, y, z))
			{
				if(hasFlushedMap == false)
				{
					//need flush map
					doDraw();
					for(int bufferIdx = 0; bufferIdx < 2; ++bufferIdx)
					{
						mVertBufferOffset[bufferIdx] = 0;
					}
				}
				
				mCoins[i].render(depth);
			}
		}		
	}
	
	//return has draw player in this call
	public boolean drawPlayer(int x, int y, int z, boolean ceilX, boolean ceilY, boolean ceilZ, float depth)	
	{
		if(mScene.getPitch() == 1.0f) //top-view, always draw player after all blocks
			return false;
		
		Player player = mScene.getPlayer();
		if(player != null && player.isInBlock(x, y, z,ceilX, ceilY, ceilZ))
		{
			//first, flush map buffer.
			doDraw();
			//clear buffer offset.
			for(int i = 0; i < 2; ++i)
			{
				mVertBufferOffset[i] = 0;
			}
			
			//then draw player
			player.render(depth);
			return true;
		} 
		
		return false;
	}
	
	public void fillFaceVertexBuffer(int[] vertexBuffer)
	{
		if(Map.PRE_FACE_VERTEX_BUFFER_SIZE + mVertBufferOffset[0] > MAX_VERTEX_BUFFER_SIZE)
		{
			Log.d("VBO warinig", "too many face vertexes, you can increase the MAX_FACES_NUM in Map.java to fix it");
			return;
		}
		
		//GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[0]);
		//GLES11.glBufferSubData(GLES11.GL_ARRAY_BUFFER, mVertBufferOffset[0], Map.PRE_FACE_VERTEX_BUFFER_SIZE, buffer);
		
		System.arraycopy(vertexBuffer, 0, mVertexArrays1, mVertBufferOffset[0] / 4, vertexBuffer.length);
		
		mVertBufferOffset[0] += Map.PRE_FACE_VERTEX_BUFFER_SIZE;
	}
	
	public void fillGridVertexBuffer(int[] vertexBuffer)
	{
		if(Map.PRE_FACE_VERTEX_BUFFER_SIZE + mVertBufferOffset[1] > MAX_VERTEX_BUFFER_SIZE)
		{
			Log.d("VBO warinig", "too many grid vertexes, you can increase the MAX_FACES_NUM in Map.java to fix it");
			return;
		}
		
		//GLES11.glBindBuffer(GLES11.GL_ARRAY_BUFFER, mVertexBufferID[1]);
		//GLES11.glBufferSubData(GLES11.GL_ARRAY_BUFFER, mVertBufferOffset[1], Map.PRE_FACE_VERTEX_BUFFER_SIZE, buffer);
		
		System.arraycopy(vertexBuffer, 0, mVertexArrays2, mVertBufferOffset[1] / 4, vertexBuffer.length);
		
		mVertBufferOffset[1] += Map.PRE_FACE_VERTEX_BUFFER_SIZE;
	}
	
	public void updateMap2D(int[][] map2D)
	{
		float pitch = mScene.getPitch();
		if(pitch == 1.0f)
		{
			for(int x = 0; x < mMapWidth; ++x)
				for(int z = 0; z < mMapDepth; ++z)
				{
					int hightestY = -1;
					for(int y = 0; y < mMapHeight; ++y)
					{
						if(mBlocks[x][y][z].mTileNum != Block.INVALID_TILENUM)
						{
							hightestY = y;
							break;
						}
					}
					
					if(hightestY > 0)
						map2D[x][z] = mBlocks[x][hightestY][z].mTileNum;
					else
						map2D[x][z] = Block.INVALID_TILENUM;
				}
		}
		else
		{
			float rotation = mScene.getRotation();
			if(rotation == Common.PI_025)	//back
			{
				for(int x = 0; x < mMapWidth; ++x)
				{
					for(int y = 0; y < mMapHeight; ++y)
					{
						int highestZ = -1;
						for(int z = mMapDepth - 1; z >= 0; --z)
						{
							if(mBlocks[mMapWidth - x - 1][y][z].mTileNum != Block.INVALID_TILENUM)
							{
								highestZ = z;
								break;
							}
						}
						
						if(highestZ > 0)
							map2D[x][y] = mBlocks[mMapWidth - x - 1][y][highestZ].mTileNum;
						else
							map2D[x][y] = Block.INVALID_TILENUM;
					}
				}
			}
			else if(rotation == Common.PI_075) //left
			{
				for(int z = 0; z < mMapDepth; ++z)
				{
					for(int y = 0; y < mMapHeight; ++y)
					{
						int lowestx = -1;
						for(int x = 0; x < mMapWidth; ++x)
						{
							if(mBlocks[x][y][mMapDepth - z - 1].mTileNum != Block.INVALID_TILENUM)
							{
								lowestx = x;
								break;
							}
						}
						
						if(lowestx > 0)
							map2D[z][y] = mBlocks[lowestx][y][mMapDepth - z - 1].mTileNum;
						else
							map2D[z][y] = Block.INVALID_TILENUM;
					}
				}
			}
			else if(rotation == Common.PI_125) //front
			{
				for(int x = 0; x < mMapWidth; ++x)
				{
					for(int y = 0; y < mMapHeight; ++y)
					{
						int lowestZ = -1;
						for(int z = 0; z < mMapDepth; ++z)
						{
							if(mBlocks[x][y][z].mTileNum != Block.INVALID_TILENUM)
							{
								lowestZ = z;
								break;
							}
						}
						
						if(lowestZ > 0)
							map2D[x][y] = mBlocks[x][y][lowestZ].mTileNum;
						else
							map2D[x][y] = Block.INVALID_TILENUM;
					}
				}
			}
			else if(rotation == Common.PI_175) //right
			{
				for(int z = 0; z < mMapDepth; ++z)
				{
					for(int y = 0; y < mMapHeight; ++y)
					{
						int hightestX = -1;
						for(int x = mMapWidth - 1; x >= 0; --x)
						{
							if(mBlocks[x][y][z].mTileNum != Block.INVALID_TILENUM)
							{
								hightestX = x;
								break;
							}
						}
						
						if(hightestX > 0)
							map2D[z][y] = mBlocks[hightestX][y][z].mTileNum;
						else
							map2D[z][y] = Block.INVALID_TILENUM;
					}
				}
			}
		}
	}
}
